package sketch.seg.cd.exp;

import java.awt.Graphics2D;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import sketch.doc.Sketch;
import sketch.ink.Stroke;
import sketch.seg.cd.CDStaticKH;
import sketch.shape.geom.prim.Point;

public class CDTemplate {

	private List<CDStroke> strokes;

	public CDTemplate() {
		strokes = new ArrayList<CDStroke>();
	}

	public static CDTemplate get() {
		if (instance == null) {
			instance = new CDTemplate();
		}
		return instance;
	}

	private static CDTemplate instance = null;

	public static CDTemplate get(Sketch sketch) {
		CDTemplate tmp = get();
		tmp.clear();
		for (Stroke stroke : sketch.getStrokes()) {
			tmp.addStroke(CDStroke.get(stroke));
		}
		return tmp;
	}

	public static CDTemplate get(File file) {
		CDTemplate tmp = get();
		tmp.readFromFile(file);
		return tmp;
	}

	public void addStroke(CDStroke stroke) {
		strokes.add(stroke);
	}

	public void draw(Graphics2D g2) {
		g2.drawString("Corner Detection Exp Template", 0, 10);

		for (CDStroke s : getStrokes()) {
			s.draw(g2);
		}
	}

	public void saveToFile(File file) {
		try {
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(file)));

			for (CDStroke stroke : getStrokes()) {
				bw.write(stroke.toString() + "\n");
			}

			bw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public List<CDStroke> getStrokes() {
		return strokes;
	}

	public void readFromFile(File file) {
		clear();

		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

			String one = null;
			while ((one = br.readLine()) != null) {
				addStroke(CDStroke.parseStroke(one));
			}

			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void readFromFiles(File[] files) {
		clear();

		for (File file : files) {
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

				String one = null;
				while ((one = br.readLine()) != null) {
					addStroke(CDStroke.parseStroke(one));
				}

				br.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void readFromFiles(String[] filenames) {
		clear();

		for (String filename : filenames) {
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filename))));

				String one = null;
				while ((one = br.readLine()) != null) {
					addStroke(CDStroke.parseStroke(one));
				}

				br.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void appendFromFile(File file) {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

			String one = null;
			while ((one = br.readLine()) != null) {
				addStroke(CDStroke.parseStroke(one));
			}

			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void appendFromFiles(File[] files) {
		for (File file : files) {
			appendFromFile(file);
		}
	}

	public void clear() {
		strokes = new ArrayList<CDStroke>();
	}

	public void mark(Point point) {
		for (CDStroke s : getStrokes()) {
			s.mark(point);
		}
	}

	public void cd(CDStaticKH cd) {
		for (CDStroke s : getStrokes()) {
			cd.setPoints(s.getPoints());
			s.setCorners(cd.getCorners());
		}
	}

	public String[][] getTemplateInf() {
		return new String[][] {
				{ "Marks", Integer.toString(_n_of_marks()) }
		};
	}

	public String[][] getCDInf() {
		double c = _n_of_corners(), s = _n_of_success();
		double m = _n_of_marks();
		return new String[][] {
				{ "Corners", Integer.toString((int)c) },
				{ "Success", Integer.toString((int)s) },
				{ "Precision", Double.toString(100*s/c) + "%" },
				{ "Recall", Double.toString(100*s/m) + "%" }
		};
	}

	public int _n_of_corners() {
		int n = 0;
		for (CDStroke s : getStrokes())
			n += s._n_of_corners();
		return n;
	}

	public int _n_of_marks() {
		int n = 0;
		for (CDStroke s : getStrokes()) {
			n += s._n_of_marks();
		}
		return n;
	}

	public int _n_of_success() {
		int n = 0;
		for (CDStroke s : getStrokes()) {
			n += s._n_of_success();
		}
		return n;
	}

	public double _d_of_precision() {
		double s = (double) _n_of_success();
		double c = (double) _n_of_corners();
		return s/c;
	}

	public double _d_of_recall() {
		double s = _n_of_success();
		double m = _n_of_marks();
		return s/m;
	}

}
